package cn.fufeiii.bt.common.web.filter;

import cn.fufeiii.bt.common.web.request.ContentReuseRequestWrapper;
import cn.hutool.core.util.ArrayUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingResponseWrapper;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.stream.Collectors;

/**
 * API记录过滤器
 * 配置{@literal logging.api.disabled=true}关闭
 *
 * @author FuFei
 */
@Slf4j
@Component
@Order(Ordered.HIGHEST_PRECEDENCE / 100)
@ConditionalOnProperty(prefix = "logging.api", name = "enabled", havingValue = "true", matchIfMissing = true)
public class ApiLogFilter extends OncePerRequestFilter {
    @Autowired
    private ApiLogFilterProperty apiLogFilterProperty;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        boolean prq = Boolean.TRUE.equals(apiLogFilterProperty.getPrintRequest());
        boolean prp = Boolean.TRUE.equals(apiLogFilterProperty.getPrintRequest());

        // 不需要打印的接口直接放行
        if (apiLogFilterProperty.getIgnoreRequestPathList().contains(request.getServletPath()) || (!prq && !prp)) {
            filterChain.doFilter(request, response);
            return;
        }

        if (!apiLogFilterProperty.getPrintHeaderList().isEmpty()) {
            String headerParam = apiLogFilterProperty.getPrintHeaderList().stream()
                    .map(it -> "[" + it + "=" + request.getHeader(it) + "]").collect(Collectors.joining());
            log.info("接口请求头:{}", headerParam);
        }

        // 按需转换
        HttpServletRequest requestToUse = prq ? new ContentReuseRequestWrapper(request) : request;
        HttpServletResponse responseToUse = prp ? new ContentCachingResponseWrapper(response) : response;
        // 消费requestWrapper中的内容
        if (prq) {
            String queryParam = requestToUse.getParameterMap().entrySet().stream()
                    .map(it -> it.getKey() + "=" + ArrayUtil.get(it.getValue(), 0)).collect(Collectors.joining("&"));
            log.info("接口入参:query->[{}],body->[{}]", queryParam, new String(((ContentReuseRequestWrapper) requestToUse).getContentAsByteArray()));
        }
        filterChain.doFilter(requestToUse, responseToUse);

        // 消费responseWrapper中的内容
        if (prp) {
            log.info("接口出参:{}", new String(((ContentCachingResponseWrapper) responseToUse).getContentAsByteArray()));
            // 把response-wrapper中的数据复制到HttpServletResponse响应中
            ((ContentCachingResponseWrapper) responseToUse).copyBodyToResponse();
        }

    }

}
